package cn.zn.modules.pz.cur.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.zn.framework.common.exception.RRException;
import cn.zn.framework.common.utils.Constant;
import cn.zn.framework.common.utils.FileUtils;
import cn.zn.framework.common.utils.PageUtils;
import cn.zn.framework.common.vo.FinanceValues;
import cn.zn.framework.redis.RedisUtils;
import cn.zn.modules.budget.inter.BudgetFreezsInter;
import cn.zn.modules.budget.inter.BudgetInfoInter;
import cn.zn.modules.budget.inter.vo.BudgetFreezsSaveRspVO;
import cn.zn.modules.budget.inter.vo.BudgetFreezsVO;
import cn.zn.modules.budget.inter.vo.BudgetInfoVO;
import cn.zn.modules.budget.inter.vo.BudgetSGForFreezsVO;
import cn.zn.modules.invoice.inter.InvoiceRecordInfoInter;
import cn.zn.modules.loan.old.inter.LoanInter;
import cn.zn.modules.loan.old.inter.vo.LoanDetailVO;
import cn.zn.modules.money.inter.MoneyInfoDetailFreezsInter;
import cn.zn.modules.money.inter.MoneyInfoInter;
import cn.zn.modules.money.inter.vo.MoneyInfoVO;
import cn.zn.modules.pz.cur.dao.TpMainMapper;
import cn.zn.modules.pz.cur.entity.*;
import cn.zn.modules.pz.cur.entity.dto.PzBudgetDTO;
import cn.zn.modules.pz.cur.entity.dto.PzDetailDTO;
import cn.zn.modules.pz.cur.entity.dto.PzQueryDTO;
import cn.zn.modules.pz.cur.service.*;
import cn.zn.modules.pz.cur.service.print.tmpl.PrintTmpl;
import cn.zn.modules.pz.cur.service.print.tmpl.PrintTmplContext;
import cn.zn.modules.pz.cur.service.print.tmpl.PrintTmplDQ;
import cn.zn.modules.pz.cur.service.print.tmpl.PrintTmplXZ;
import cn.zn.modules.pz.enums.ExpenseWayEnum;
import cn.zn.modules.pz.enums.PayTypeEnum;
import cn.zn.modules.pz.enums.ProcessTypeEnum;
import cn.zn.modules.pz.enums.SpendingTypeEnum;
import cn.zn.modules.pz.his.entity.dto.IPzDTO;
import cn.zn.modules.pz.his.entity.vo.*;
import cn.zn.modules.pz.inter.ElecSignService;
import cn.zn.modules.pz.inter.values.PzConf;
import cn.zn.modules.pz.inter.vo.ElecSignVO;
import cn.zn.modules.pz.inter.vo.PzForInvoiceVO;
import cn.zn.modules.zzsys.inter.TeacherInter;
import cn.zn.modules.zzsys.inter.vo.TeacherInfoVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TpMainServiceImpl extends ServiceImpl<TpMainMapper, TpMain> implements TpMainService {
    @Autowired
    private FinanceValues financeValues;
    @Autowired
    private PzConf pzConf;
    @Autowired
    FileUtils fileUtils;
    @Autowired
    TpSpendingService tpSpendingService;
    @Autowired
    TpExpenseService tpExpenseService;
    @Autowired
    TpRepayService tpRepayService;
    @Autowired
    TpsFundingSourceService tpsFundingSourceService;
    @Autowired
    TpeFundingSourceService tpeFundingSourceService;
    @Autowired
    TpRepayBudgetService tpRepayBudgetService;
    @Autowired
    TpeMoneyService tpeMoneyService;
    @Autowired
    TpRepayMoneyService tpRepayMoneyService;
    @Autowired
    private TpMoneyService tpMoneyService;
    @Autowired
    TpePayService tpePayService;
    @Autowired
    TpRepayPayService tpRepayPayService;
    @Autowired
    TpbTripTrafficService tpbTripTrafficService;
    @Autowired
    TpAssociatedService tpAssociatedService;
    @Autowired
    TpAttachmentService tpAttachmentService;
    @Autowired
    private RedisUtils redisUtils;
    /**
     * 借款接口
     */
    @Autowired
    LoanInter loanInter;
    /**
     * 预算接口
     */
    @Autowired(required = false)
    BudgetInfoInter budgetInfoInter;
    @Autowired(required = false)
    BudgetFreezsInter budgetFreezsInter;
    /**
     * 经费接口
     */
    @Autowired(required = false)
    MoneyInfoInter moneyInfoInter;
    @Autowired(required = false)
    InvoiceRecordInfoInter invoiceRecordInfoInter;
    /**
     * 电子签章接口
     */
    @Autowired
    private ElecSignService elecSignService;
    @Autowired
    private TeacherInter teacherInter;
    @Autowired
    private MoneyInfoDetailFreezsInter moneyInfoDetailFreezsInter;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveMoneyType(String id, Boolean isCash) {
        TpMain tpMain = super.getById(id);
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
        switch (processTypeEnum){
            case EXPENSE:
                TpExpense tpExpense = tpExpenseService.findByMainId(id);
                // 修改是否现金
                TpExpense tpExpenseSave = new TpExpense();
                tpExpenseSave.setId(tpExpense.getId());
                tpExpenseSave.setMoneyTypeIscash(isCash);
                tpExpenseService.updateById(tpExpenseSave);
                break;
            case REPAY:
                TpRepay tpRepay = tpRepayService.findByMainId(id);
                // 修改是否现金
                TpRepay tpRepaySave = new TpRepay();
                tpRepaySave.setId(tpRepay.getId());
                tpRepaySave.setMoneyTypeIscash(isCash);
                tpRepayService.updateById(tpRepaySave);
                break;
        }
        if(isCash){
            // 现金不再设置经费来源
            // 统一操作，从经费冻结删除
            tpMoneyService.queryByMainId(id).forEach(o->{
                moneyInfoDetailFreezsInter.delete(o.getMoneyFreezeId());
            });
        }
    }

    @Override
    public PageUtils queryPage(PzQueryDTO dto) {
        IPage page = dto.getPage();
        List<TpMain> list = baseMapper.findList(dto, page);
        if (list.size() == 0) {
            return new PageUtils(page);
        }
        Map<String, TpMain> tpMainMap = list.stream().collect(Collectors.toMap(TpMain::getId, o -> o, (o1, o2) -> o1, LinkedHashMap::new));
        // 查询对应业务数据
        List<PzListVO> pzListVOS = Lists.newArrayList();
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(dto.getApplyType());
        PzListVO pzListVO;
        TpExpense tpExpense;
        Map<String, List<String>> budgetMainMap = CollUtil.newHashMap();
        switch (processTypeEnum) {
            case SPENDING:
                for (String key : tpMainMap.keySet()) {
                    pzListVO = new PzListVO();
                    BeanUtils.copyProperties(tpMainMap.get(key), pzListVO);
                    pzListVOS.add(pzListVO);
                    // 预算
                    tpsFundingSourceService.findByMainId(key).forEach(o -> {
                        if (!budgetMainMap.containsKey(o.getBudgetInfoId())) {
                            budgetMainMap.put(o.getBudgetInfoId(), CollUtil.newArrayList());
                        }
                        budgetMainMap.get(o.getBudgetInfoId()).add(key);
                    });
                }
                break;
            case EXPENSE:
                QueryWrapper<TpExpense> queryWrapper_E = Wrappers.query();
                queryWrapper_E.in("TP_MAIN_ID_", tpMainMap.keySet());
                Map<String, TpExpense> tpExpenseMap = tpExpenseService.list(queryWrapper_E).stream().collect(Collectors.toMap(TpExpense::getTpMainId, o -> o));
                List<String> applyCodes = tpMainMap.entrySet().stream().map(o -> o.getValue().getApplyCode()).collect(Collectors.toList());
                Map<String, LoanDetailVO> loanMap = loanInter != null ? loanInter.findByApplyCodes(applyCodes).stream().collect(Collectors.toMap(LoanDetailVO::getApplyCode, o -> o)) : null;
                for (String key : tpMainMap.keySet()) {
                    pzListVO = new PzListVO();
                    BeanUtils.copyProperties(tpMainMap.get(key), pzListVO);
                    tpExpense = tpExpenseMap.get(key);
                    if (tpExpense != null) {
                        pzListVO.setIsExistApply(tpExpense.getIsExistApply());
                        pzListVO.setReason(tpExpense.getReason());
                        pzListVO.setIsAppoint(tpExpense.getIsAppoint());
                    }
                    if (loanMap != null) {
                        LoanDetailVO loanDetailVO = loanMap.get(tpMainMap.get(key).getApplyCode());
                        if (loanDetailVO != null) {
                            pzListVO.setIsExistLoan(loanDetailVO != null);
                            pzListVO.setIsLoanDeal(loanDetailVO.getIsDeal());
                        }
                    }
                    pzListVOS.add(pzListVO);
                    // 预算
                    tpeFundingSourceService.findByMainId(key).forEach(o -> {
                        if (!budgetMainMap.containsKey(o.getBudgetInfoId())) {
                            budgetMainMap.put(o.getBudgetInfoId(), CollUtil.newArrayList());
                        }
                        budgetMainMap.get(o.getBudgetInfoId()).add(key);
                    });
                }
                break;
            case REPAY:
                for (String key : tpMainMap.keySet()) {
                    pzListVO = new PzListVO();
                    BeanUtils.copyProperties(tpMainMap.get(key), pzListVO);
                    pzListVOS.add(pzListVO);
                    // 预算
                    tpRepayBudgetService.findByMainId(key).forEach(o -> {
                        if (!budgetMainMap.containsKey(o.getBudgetInfoId())) {
                            budgetMainMap.put(o.getBudgetInfoId(), CollUtil.newArrayList());
                        }
                        budgetMainMap.get(o.getBudgetInfoId()).add(key);
                    });
                }
                break;
            default:
                break;
        }
        // 预算(mainId)
        Map<String, List<BudgetInfoVO>> budgetInfoVOMap = CollUtil.newHashMap();
        if (budgetInfoInter != null) {
            budgetInfoInter.findByIds(CollUtil.newArrayList(budgetMainMap.keySet())).forEach(o -> {
                List<String> mainIds = budgetMainMap.get(o.getId());
                mainIds.forEach(o1 -> {
                    if (!budgetInfoVOMap.containsKey(o1)) {
                        budgetInfoVOMap.put(o1, CollUtil.newArrayList());
                    }
                    budgetInfoVOMap.get(o1).add(o);
                });
            });
        }
        // 双高(mainId)
        Map<String, List<BudgetSGForFreezsVO>> sgInfoVOMap = this.sgInfos(CollUtil.newArrayList(tpMainMap.keySet()));
        if (budgetInfoVOMap.size() > 0 || sgInfoVOMap.size() > 0) {
            pzListVOS.forEach(o -> {
                if (budgetInfoVOMap != null && budgetInfoVOMap.get(o.getId()) != null) {
                    o.setBudgetProjects(budgetInfoVOMap.get(o.getId()).stream().map(BudgetInfoVO::getProjectName).collect(Collectors.toList()));
                }
                if (sgInfoVOMap != null && sgInfoVOMap.get(o.getId()) != null) {
                    o.setSgFreezsList(sgInfoVOMap.get(o.getId()));
                }
            });
        }
        IPage<PzListVO> pageVO = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        pageVO.setRecords(pzListVOS);
        return new PageUtils(pageVO);
    }

    @Override
    public TpMain findByAppontMainId(String mainId) {
        return this.baseMapper.findByAppontMainId(mainId);
    }

    @Override
    public IPz findDetail(PzDetailDTO pzDetailDTO) {
        IPz pz = null;
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(pzDetailDTO.getApplyType());
        switch (processTypeEnum) {
            case SPENDING:
                pz = new PzRequestVO();
                break;
            case EXPENSE:
                PzExpenseVO pzExpenseVO = new PzExpenseVO();
                TpExpense tpExpense = tpExpenseService.findByMainId(pzDetailDTO.getMainId());
                if (StrUtil.isNotBlank(tpExpense.getExpenseWay())) {
                    pzExpenseVO.setExpenseWay(tpExpense.getExpenseWay());
                    pzExpenseVO.setExpenseWayName(ExpenseWayEnum.findByCode(tpExpense.getExpenseWay()).getName());
                }
                pzExpenseVO.setPaperNum(tpExpense.getPaperNum());
                pz = pzExpenseVO;
                break;
            case REPAY:
                PzRepayVO pzRepayVO = new PzRepayVO();
                TpRepay tpRepay = tpRepayService.findByMainId(pzDetailDTO.getMainId());
                if (StrUtil.isNotBlank(tpRepay.getExpenseWay())) {
                    pzRepayVO.setExpenseWay(tpRepay.getExpenseWay());
                    pzRepayVO.setExpenseWayName(ExpenseWayEnum.findByCode(tpRepay.getExpenseWay()).getName());
                }
                pzRepayVO.setPaperNum(tpRepay.getPaperNum());
                pz = pzRepayVO;
                break;
            default:
                break;
        }
        TpMain tpMain = this.getBaseMapper().findDetail(pzDetailDTO.getMainId());
        if (tpMain != null && pz != null) {
            PzMainVO pzMainVO = new PzMainVO();
            BeanUtils.copyProperties(tpMain, pzMainVO);
            pzMainVO.setMainId(tpMain.getId());
            pz.setPzMainVO(pzMainVO);
        }
        return pz;
    }

    @Override
    public List<PzBudgetVO> findBudgetByMainId(String mainId) {
        List<PzBudgetVO> pzBudgetVOS = Lists.newArrayList();
        List<String> budgetInfoIds = Lists.newArrayList();
        TpMain tpMain = this.getById(mainId);
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
        switch (processTypeEnum) {
            case SPENDING:
                pzBudgetVOS = tpsFundingSourceService.findByMainId(mainId).stream().map(o -> {
                    budgetInfoIds.add(o.getBudgetInfoId());
                    PzBudgetVO pzBudgetVO = new PzBudgetVO();
                    BeanUtils.copyProperties(o, pzBudgetVO);
                    return pzBudgetVO;
                }).collect(Collectors.toList());
                break;
            case EXPENSE:
                pzBudgetVOS = tpeFundingSourceService.findByMainId(mainId).stream().map(o -> {
                    budgetInfoIds.add(o.getBudgetInfoId());
                    PzBudgetVO pzBudgetVO = new PzBudgetVO();
                    BeanUtils.copyProperties(o, pzBudgetVO);
                    return pzBudgetVO;
                }).collect(Collectors.toList());
                break;
            case REPAY:
                pzBudgetVOS = tpRepayBudgetService.findByMainId(mainId).stream().map(o -> {
                    budgetInfoIds.add(o.getBudgetInfoId());
                    PzBudgetVO pzBudgetVO = new PzBudgetVO();
                    BeanUtils.copyProperties(o, pzBudgetVO);
                    return pzBudgetVO;
                }).collect(Collectors.toList());
                break;
            default:
                break;
        }
        if (budgetInfoInter != null) {
            // 预算的部门及项目
            Map<String, BudgetInfoVO> budgetInfoVOMap = budgetInfoInter.findByIds(budgetInfoIds).stream().collect(Collectors.toMap(BudgetInfoVO::getId, o -> o));
            for (PzBudgetVO pzBudgetVO : pzBudgetVOS) {
                if (StrUtil.isNotBlank(pzBudgetVO.getBudgetInfoId()) && budgetInfoVOMap.containsKey(pzBudgetVO.getBudgetInfoId())) {
                    pzBudgetVO.setProjectCode(budgetInfoVOMap.get(pzBudgetVO.getBudgetInfoId()).getProjectCode());
                    pzBudgetVO.setProjectName(budgetInfoVOMap.get(pzBudgetVO.getBudgetInfoId()).getProjectName());
                    pzBudgetVO.setDeptCode(budgetInfoVOMap.get(pzBudgetVO.getBudgetInfoId()).getDeptCode());
                    pzBudgetVO.setDeptName(budgetInfoVOMap.get(pzBudgetVO.getBudgetInfoId()).getDeptName());
                }
            }
        }
        return pzBudgetVOS;
    }

    @Override
    public PzBudgetVO findBudgetByIdAndMainId(String id, String mainId) {
        PzBudgetVO pzBudgetVO = new PzBudgetVO();
        TpMain tpMain = this.getById(mainId);
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
        switch (processTypeEnum) {
            case SPENDING:
                TpsFundingSource tpsFundingSource = tpsFundingSourceService.getById(id);
                BeanUtils.copyProperties(tpsFundingSource, pzBudgetVO);
                break;
            case EXPENSE:
                TpeFundingSource tpeFundingSource = tpeFundingSourceService.getById(id);
                BeanUtils.copyProperties(tpeFundingSource, pzBudgetVO);
                break;
            case REPAY:
                TpRepayBudget tpRepayBudget = tpRepayBudgetService.getById(id);
                BeanUtils.copyProperties(tpRepayBudget, pzBudgetVO);
                break;
            default:
                break;
        }
        if (budgetInfoInter != null) {
            List<BudgetInfoVO> budgetInfoVOList = budgetInfoInter.findByIds(CollUtil.newArrayList(pzBudgetVO.getBudgetInfoId()));
            if (budgetInfoVOList.size() > 0) {
                pzBudgetVO.setProjectCode(budgetInfoVOList.get(0).getProjectCode());
                pzBudgetVO.setProjectName(budgetInfoVOList.get(0).getProjectName());
                pzBudgetVO.setDeptCode(budgetInfoVOList.get(0).getDeptCode());
                pzBudgetVO.setDeptName(budgetInfoVOList.get(0).getDeptName());
            }
        }
        return pzBudgetVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBudget(PzBudgetDTO pzBudgetDTO) {
        TpMain tpMain = this.getById(pzBudgetDTO.getMainId());
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
        String freezsId = "";
        if (StrUtil.isNotBlank(pzBudgetDTO.getId())) {
            // 查询冻结
            switch (processTypeEnum) {
                case SPENDING:
                    TpsFundingSource tpsFundingSource = tpsFundingSourceService.getById(pzBudgetDTO.getId());
                    freezsId = tpsFundingSource.getBudgetFreezsId();
                    break;
                case EXPENSE:
                    TpeFundingSource tpeFundingSource = tpeFundingSourceService.getById(pzBudgetDTO.getId());
                    freezsId = tpeFundingSource.getBudgetFreezsId();
                    break;
                case REPAY:
                    TpRepayBudget tpRepayBudget = tpRepayBudgetService.getById(pzBudgetDTO.getId());
                    freezsId = tpRepayBudget.getBudgetFreezsId();
                    break;
                default:
            }
        }
        // 冻结预算
        BudgetFreezsSaveRspVO budgetFreezsSaveRspVO = null;
        if (!pzBudgetDTO.getNoBudget()) {
            // 设置经费，保存或更新冻结
            if (budgetFreezsInter == null) {
                throw new RRException("未加载预算模块");
            }
            budgetFreezsSaveRspVO = budgetFreezsInter.saveBudgetFreezs(BudgetFreezsVO.builder()
                    .id(freezsId)
                    .deptCode(pzBudgetDTO.getDeptCode())
                    .projectCode(pzBudgetDTO.getProjectCode())
                    .cateCode(pzBudgetDTO.getCateCode())
                    .money(pzBudgetDTO.getMoney())
                    .build());
        }
        switch (processTypeEnum) {
            case SPENDING:
                TpSpending tpSpending = tpSpendingService.findByMainId(pzBudgetDTO.getMainId());
                TpsFundingSource tpsFundingSource = new TpsFundingSource();
                BeanUtils.copyProperties(pzBudgetDTO, tpsFundingSource);
                tpsFundingSource.setTpSpendingId(tpSpending.getId());
                tpsFundingSource.setBudgetInfoId(budgetFreezsSaveRspVO != null ? budgetFreezsSaveRspVO.getInfoId() : null);
                tpsFundingSource.setBudgetFreezsId(budgetFreezsSaveRspVO != null ? budgetFreezsSaveRspVO.getFreezsId() : null);
                tpsFundingSourceService.saveOrUpdate(tpsFundingSource);
                break;
            case EXPENSE:
                TpExpense tpExpense = tpExpenseService.findByMainId(pzBudgetDTO.getMainId());
                TpeFundingSource tpeFundingSource = new TpeFundingSource();
                BeanUtils.copyProperties(pzBudgetDTO, tpeFundingSource);
                tpeFundingSource.setTpExpenseId(tpExpense.getId());
                tpeFundingSource.setBudgetInfoId(budgetFreezsSaveRspVO != null ? budgetFreezsSaveRspVO.getInfoId() : null);
                tpeFundingSource.setBudgetFreezsId(budgetFreezsSaveRspVO != null ? budgetFreezsSaveRspVO.getFreezsId() : null);
                tpeFundingSourceService.saveOrUpdate(tpeFundingSource);
                break;
            case REPAY:
                TpRepay tpRepay = tpRepayService.findByMainId(pzBudgetDTO.getMainId());
                TpRepayBudget tpRepayBudget = new TpRepayBudget();
                BeanUtils.copyProperties(pzBudgetDTO, tpRepayBudget);
                tpRepayBudget.setTpRepayId(tpRepay.getId());
                tpRepayBudget.setBudgetInfoId(budgetFreezsSaveRspVO != null ? budgetFreezsSaveRspVO.getInfoId() : null);
                tpRepayBudget.setBudgetFreezsId(budgetFreezsSaveRspVO != null ? budgetFreezsSaveRspVO.getFreezsId() : null);
                tpRepayBudgetService.saveOrUpdate(tpRepayBudget);
                break;
            default:
        }
        if (pzBudgetDTO.getNoBudget() && StrUtil.isNotBlank(freezsId)) {
            // 存在冻结的需要删除
            budgetFreezsInter.deleteBudgetFreezs(CollUtil.newArrayList(freezsId));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBudget(String mainId, List<String> ids) {
        TpMain tpMain = this.getById(mainId);
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
        List<String> freezsIds = CollUtil.newArrayList();
        // 查询冻结
        switch (processTypeEnum) {
            case SPENDING:
                freezsIds = tpsFundingSourceService.listByIds(ids).stream().filter(o -> StrUtil.isNotBlank(o.getBudgetFreezsId())).map(o -> o.getBudgetFreezsId()).collect(Collectors.toList());
                tpsFundingSourceService.removeByIds(ids);
                break;
            case EXPENSE:
                freezsIds = tpeFundingSourceService.listByIds(ids).stream().filter(o -> StrUtil.isNotBlank(o.getBudgetFreezsId())).map(o -> o.getBudgetFreezsId()).collect(Collectors.toList());
                tpeFundingSourceService.removeByIds(ids);
                break;
            case REPAY:
                freezsIds = tpRepayBudgetService.listByIds(ids).stream().filter(o -> StrUtil.isNotBlank(o.getBudgetFreezsId())).map(o -> o.getBudgetFreezsId()).collect(Collectors.toList());
                tpRepayBudgetService.removeByIds(ids);
                break;
            default:
        }
        if (budgetFreezsInter != null && !freezsIds.isEmpty()) {
            budgetFreezsInter.deleteBudgetFreezs(freezsIds);
        }
    }

    @Override
    public List<PzMoneyVO> findMoneyByMainId(String mainId) {
        List<PzMoneyVO> pzMoneyVOS = Lists.newArrayList();
        List<String> moneyInfoIds = Lists.newArrayList();
        TpMain tpMain = this.getById(mainId);
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
        switch (processTypeEnum) {
            case EXPENSE:
                pzMoneyVOS = tpeMoneyService.findByMainId(mainId).stream().map(o -> {
                    moneyInfoIds.add(o.getMoneyInfoId());
                    PzMoneyVO pzMoneyVO = new PzMoneyVO();
                    BeanUtils.copyProperties(o, pzMoneyVO);
                    return pzMoneyVO;
                }).collect(Collectors.toList());
                break;
            case REPAY:
                pzMoneyVOS = tpRepayMoneyService.findByMainId(mainId).stream().map(o -> {
                    moneyInfoIds.add(o.getMoneyInfoId());
                    PzMoneyVO pzMoneyVO = new PzMoneyVO();
                    BeanUtils.copyProperties(o, pzMoneyVO);
                    return pzMoneyVO;
                }).collect(Collectors.toList());
                break;
            default:
                break;
        }
        if (moneyInfoInter != null) {
            Map<String, MoneyInfoVO> moneyInfoVOMap = moneyInfoInter.findByIds(moneyInfoIds).stream().collect(Collectors.toMap(MoneyInfoVO::getId, o -> o));
            // 记录经济分类，冻结的预算经济分类有可能不同
            String cateName;
            for (PzMoneyVO pzMoneyVO : pzMoneyVOS) {
                cateName = pzMoneyVO.getCateName();
                if (StrUtil.isNotBlank(pzMoneyVO.getMoneyInfoId()) && moneyInfoVOMap.containsKey(pzMoneyVO.getMoneyInfoId())) {
                    BeanUtils.copyProperties(moneyInfoVOMap.get(pzMoneyVO.getMoneyInfoId()), pzMoneyVO);
                    pzMoneyVO.setCateName(cateName);
                }
            }
        }
        return pzMoneyVOS;
    }

    @Override
    public List<PzPayVO> findPayByMainId(String mainId) {
        List<PzPayVO> pzPayVOS = Lists.newArrayList();
        TpMain tpMain = this.getById(mainId);
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
        switch (processTypeEnum) {
            case EXPENSE:
                pzPayVOS = tpePayService.findByMainId(mainId).stream().map(o -> {
                    PzPayVO pzPayVO = new PzPayVO();
                    BeanUtils.copyProperties(o, pzPayVO);
                    pzPayVO.setPayTypeName(PayTypeEnum.findByCode(o.getPayTypeCode()).getName());
                    return pzPayVO;
                }).collect(Collectors.toList());
                break;
            case REPAY:
                pzPayVOS = tpRepayPayService.findByMainId(mainId).stream().map(o -> {
                    PzPayVO pzPayVO = new PzPayVO();
                    BeanUtils.copyProperties(o, pzPayVO);
                    pzPayVO.setPayTypeName(PayTypeEnum.findByCode(o.getPayTypeCode()).getName());
                    return pzPayVO;
                }).collect(Collectors.toList());
                break;
            default:
                break;
        }
        return pzPayVOS;
    }

    @Override
    public PzTicketVO findTicket(String mainId) {
        TpMain tpMain = this.baseMapper.findDetail(mainId);
        PzTicketVO pzTicket = null;
        if (tpMain != null) {
            IPz iPz;
            PzMainVO pzMainVO = new PzMainVO();
            BeanUtil.copyProperties(tpMain, pzMainVO);
            String templateName;
            ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
            switch (processTypeEnum) {
                case SPENDING:
                    iPz = new PzRequestVO();
                    TpSpending tpSpending = tpSpendingService.findByMainId(mainId);
                    BeanUtils.copyProperties(tpSpending, iPz);
                    iPz.setPzMainVO(pzMainVO);
                    // 出差
                    List<PzTripVO> pzTripVOS = null;
                    if (tpSpending.getSpendingType() == 2) {
                        pzTripVOS = tpbTripTrafficService.findByMainId(mainId);
                    }
                    // 查询预算
                    List<PzBudgetVO> budgetVOS = this.findBudgetByMainId(mainId);
                    pzTicket = this.buildSpending((PzRequestVO) iPz, pzTripVOS, budgetVOS);
                    break;
                case EXPENSE:
                    iPz = new PzExpenseVO();
                    TpExpense tpExpense = tpExpenseService.findByMainId(mainId);
                    BeanUtils.copyProperties(tpExpense, iPz);
                    iPz.setPzMainVO(pzMainVO);
                    // 模板名称
                    if (tpExpense.getSpendingType() == 4 || tpExpense.getSpendingType() == 5) {
                        templateName = "myPrint2_2";
                    } else {
                        templateName = "myPrint2_1";
                        // 查询是否存在借款
                        if (loanInter != null) {
                            Double loanMoney = loanInter.findLoan(tpMain.getApplyCode());
                            if (loanMoney != null && Double.compare(loanMoney, 0D) > 0) {
                                ((PzExpenseVO) iPz).setLoanMoney(loanMoney);
                                templateName = "myPrint2_3";
                            }
                        }
                    }
                    // 当预算明细为不同部门时，预算部门显示为“采购小组”
                    List<PzBudgetVO> pzBudgetVOS = this.findBudgetByMainId(mainId);
                    if (pzBudgetVOS != null) {
                        String deptCode = "";
                        for (PzBudgetVO pzBudgetVO : pzBudgetVOS) {
                            if (!StrUtil.isNotBlank(deptCode)) {
                                deptCode = pzBudgetVO.getDeptCode();
                            } else {
                                if (!deptCode.equals(pzBudgetVO.getDeptCode())) {
                                    iPz.setApplyDeptName("采购小组");
                                    break;
                                }
                            }
                        }
                    }
                    // 查询经费
                    StringBuilder moneyNameBuffer = new StringBuilder();
                    if (((PzExpenseVO) iPz).getMoneyTypeIscash()) {
                        moneyNameBuffer.append("现金");
                    } else {
                        List<PzMoneyVO> pzMoneyVOS = this.findMoneyByMainId(mainId);
                        List<String> moneyNames = pzMoneyVOS.stream().limit(2).map(o -> o.getMoneyTypeName().concat("-").concat(o.getProjectName())).collect(Collectors.toList());
                        for (int i = 0; i < moneyNames.size(); i++) {
                            moneyNameBuffer.append(moneyNames.get(i));
                            if (i < moneyNames.size() - 1) {
                                moneyNameBuffer.append("<br/>");
                            }
                        }
                        if (pzMoneyVOS.size() > 2) {
                            moneyNameBuffer.append("，等");
                        }
                    }
                    ((PzExpenseVO) iPz).setMoneyStr(moneyNameBuffer.toString());
                    ((PzExpenseVO) iPz).setPrintTime(Calendar.getInstance().getTime());
                    pzTicket = PzTicketVO.builder()
                            .templateName(templateName)
                            .pz(iPz)
                            .build();
                    break;
                case REPAY:
                    iPz = new PzRepayVO();
                    TpRepay tpRepay = tpRepayService.findByMainId(mainId);
                    BeanUtils.copyProperties(tpRepay, iPz);
                    iPz.setPzMainVO(pzMainVO);
                    // 模板名称
                    if (tpRepay.getSpendingType() == 4 || tpRepay.getSpendingType() == 5) {
                        templateName = "myPrint2_2";
                    } else {
                        templateName = "myPrint2_1";
                    }
                    // 当预算明细为不同部门时，预算部门显示为“采购小组”
                    List<PzBudgetVO> pzBudgetVOS_R = this.findBudgetByMainId(mainId);
                    if (pzBudgetVOS_R != null) {
                        String deptCode = "";
                        for (PzBudgetVO pzBudgetVO : pzBudgetVOS_R) {
                            if (!StrUtil.isNotBlank(deptCode)) {
                                deptCode = pzBudgetVO.getDeptCode();
                            } else {
                                if (!deptCode.equals(pzBudgetVO.getDeptCode())) {
                                    iPz.setApplyDeptName("采购小组");
                                    break;
                                }
                            }
                        }
                    }
                    // 还款单，不打印经费信息
                    //pzRepayVO.setMoneyStr(this.buildMoneyStr(pzRepay.getMoneyTypeIscash(), ap, mainId));
                    ((PzRepayVO) iPz).setPrintTime(Calendar.getInstance().getTime());
                    pzTicket = PzTicketVO.builder()
                            .templateName(templateName)
                            .pz(iPz)
                            .build();
                    break;
                default:
            }
            // 查询审批
            Map<String, String> auditMap = CollUtil.newHashMap();
            // 查询电子签章
            Map<String, ElecSignVO> signMap = CollUtil.newHashMap();
            if (elecSignService != null) {
                Map<String, ElecSignVO> querySignMap = elecSignService.findSigns(tpMain.getApplyCode()).stream().collect(Collectors.toMap(ElecSignVO::getUserCode, item -> item, (o1, o2) -> o1));
                signMap.putAll(querySignMap);
            }
            // 查询审批
            this.baseMapper.findAudit(mainId).forEach(pzAudit -> {
                String imgData = StrUtil.isNotBlank(pzAudit.getSignImgPath()) ? financeValues.getFile().getDomain() + pzAudit.getSignImgPath() : "";
                if (!signMap.isEmpty() && signMap.containsKey(pzAudit.getAssigneeCode())) {
                    ElecSignVO elecSignVO = signMap.get(pzAudit.getAssigneeCode());
                    switch (elecSignVO.getElecSignType()) {
                        case URL:
                            imgData = elecSignVO.getContent();
                            break;
                        case BASE64:
                            imgData = "data:image/jpeg;base64," + elecSignVO.getContent();
                            break;
                    }
                }
                auditMap.put(pzAudit.getGroupCode(), StrUtil.isNotBlank(pzAudit.getSignImgPath()) ? "" : pzAudit.getAssigneeName());
                auditMap.put(pzAudit.getGroupCode().concat("Img"), imgData);
                auditMap.put(pzAudit.getGroupCode().concat("ConfirmImg"), StrUtil.isNotBlank(pzAudit.getConfirmImgPath()) ? financeValues.getFile().getDomain() + pzAudit.getConfirmImgPath() : "");
                auditMap.put(pzAudit.getGroupCode().concat("Time"), pzAudit.getEndTime() != null ? pzAudit.getEndTime().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")) : "");
            });
            pzTicket.setAuditMap(auditMap);
            pzTicket.setQrCodeUrl("/common/qrCode?content=" + tpMain.getApplyCode());
            pzTicket.setSchoolName(financeValues.getCommon().getSysName());
        }
        return pzTicket;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public IPz newApply(String applyType, String applyUserCode) {
        if (teacherInter == null) {
            throw new RRException("未加载教师模块");
        }
        TpMain tpMain = this.getOne(new QueryWrapper<TpMain>().eq("STATE_", 0)
                .eq("APPLY_TYPE_", applyType)
                .eq("APPLY_USER_CODE_", applyUserCode));
        if (tpMain == null) {
            TeacherInfoVO teacherInfoVO = teacherInter.findByWorkNo(applyUserCode);
            tpMain = TpMain.builder()
                    .applyUserCode(applyUserCode)
                    .agentUsers(teacherInfoVO.getName())
                    .applyType(applyType)
                    .applyDate(Calendar.getInstance().getTime())
                    .build();
            this.save(tpMain);
            ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
            switch (processTypeEnum) {
                case SPENDING:
                    tpSpendingService.save(TpSpending.builder()
                            .tpMainId(tpMain.getId())
                            .build());
                    break;
                case EXPENSE:
                    tpExpenseService.save(TpExpense.builder()
                            .tpMainId(tpMain.getId())
                            .build());
                    break;
            }
        } else {
            this.update(new UpdateWrapper<TpMain>()
                    .set("APPLY_DATE_", Calendar.getInstance().getTime())
                    .eq("ID_", tpMain.getId())
            );
        }
        return this.findDetail(PzDetailDTO.builder()
                .applyType(applyType)
                .mainId(tpMain.getId())
                .build());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveApply(IPzDTO iPz) {
        TpMain tpMain = new TpMain();
        BeanUtils.copyProperties(iPz, tpMain);
        tpMain.setId(iPz.getMainId());
        if (StrUtil.isBlank(tpMain.getApplyCode())) {
            ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
            tpMain.setApplyCode(
                    processTypeEnum.getPrefix().concat(String.valueOf(Calendar.getInstance().getTimeInMillis()))
                            .concat(RandomUtil.randomNumbers(3)));
        }
        if (tpMain.getState() == 0) {
            tpMain.setState(1);
        }
        String mainId = tpMain.getId();
        this.update(tpMain, new UpdateWrapper<TpMain>().eq("ID_", mainId));
        // 保存其他信息
        tpMain = this.getById(tpMain.getId());
        ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(tpMain.getApplyType());
        switch (processTypeEnum) {
            case SPENDING:
                TpSpending tpSpending = new TpSpending();
                BeanUtils.copyProperties(iPz, tpSpending);
                tpSpendingService.update(tpSpending, new UpdateWrapper<TpSpending>().eq("TP_MAIN_ID_", mainId));
                break;
            case EXPENSE:
                TpExpense tpExpense = new TpExpense();
                BeanUtils.copyProperties(iPz, tpExpense);
                tpExpenseService.update(tpExpense, new UpdateWrapper<TpExpense>().eq("TP_MAIN_ID_", mainId));
                break;
            case REPAY:
                TpRepay tpRepay = new TpRepay();
                BeanUtils.copyProperties(iPz, tpRepay);
                tpRepayService.update(tpRepay, new UpdateWrapper<TpRepay>().eq("TP_MAIN_ID_", mainId));
                break;
        }
    }

    @Override
    public long findCountToAppoint(String userCode) {
        return baseMapper.findCountToAppoint(userCode);
    }

    @Override
    public void saveAuth(String mainId, String authToUserCode) {
        TpMain tpMain = super.getById(mainId);
        if (tpMain == null) {
            throw new RRException("单据不存在!");
        }
        if (StringUtils.isNotBlank(tpMain.getAuthUserCode())) {
            throw new RRException("此单据已经被委托!");
        }
        super.update(new UpdateWrapper<TpMain>().eq("ID_", mainId)
                .set("AUTH_USER_CODE_", tpMain.getApplyUserCode())
                .set("APPLY_USER_CODE_", authToUserCode)
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveForExpense(String mainId, SpendingTypeEnum spendingTypeEnum) {
        /*请示流程结束后需要进行的操作
        1.修改请示状态、关联信息
        2.生成报销单信息
        3.更新预算冻结信息
        */
        // 设置结束
        TpMain tpMain = super.getById(mainId);
        if (tpMain == null) {
            log.error("流程主表不存在：mainId={}", mainId);
            throw new RRException("流程主表不存在");
        }
        // 判断是否是请示
        if (!ProcessTypeEnum.findByDeployKey(tpMain.getApplyType()).equals(ProcessTypeEnum.SPENDING)) {
            throw new RRException("此单据不是请示单");
        }
        // 信息转移到报销
        TpSpending tpSpending = tpSpendingService.findByMainId(mainId);
        if (tpSpending == null) {
            log.error("流程信息不存在：mainId={}", mainId);
            throw new RRException("流程信息不存在");
        }
        // 设置已报销
        tpSpendingService.update(new UpdateWrapper<TpSpending>()
                .eq("ID_", tpSpending.getId())
                .set("IS_EXPENSE_", true)
        );
        // 生成报销主表
        TpMain tpMainExpense = new TpMain();
        BeanUtils.copyProperties(tpMain, tpMainExpense);
        tpMainExpense.setId(null);
        tpMainExpense.setApplyDate(new Date());
        tpMainExpense.setTitle(tpMain.getTitle().concat("报销单"));
        tpMainExpense.setApplyCode(ProcessTypeEnum.EXPENSE.getPrefix().concat(String.valueOf(Calendar.getInstance().getTimeInMillis()))
                .concat(RandomUtil.randomNumbers(3)));
        tpMainExpense.setApplyType(ProcessTypeEnum.EXPENSE.getDeployKey());
        tpMainExpense.setState(1);
        super.save(tpMainExpense);
        // 添加关联信息
        TpAssociated tpAssociated = new TpAssociated();
        tpAssociated.setTpMainId(tpMainExpense.getId());
        tpAssociated.setProcessCode(tpMain.getApplyCode());
        tpAssociatedService.save(tpAssociated);
        // 更新事前请示关联
        super.update(new UpdateWrapper<TpMain>()
                .eq("ID_", mainId)
                .set("ASSOCIATED_CODE_", tpMainExpense.getApplyCode())
                .set("IS_ASSOCIATED_", true)
        );
        // 报销信息
        TpExpense tpExpense = new TpExpense();
        tpExpense.setTpMainId(tpMainExpense.getId());
        tpExpense.setIsUsePublic(tpSpending.getIsUsePublic());
        tpExpense.setIsExistApply(true);
        tpExpense.setMoney(tpSpending.getMoney());
        tpExpense.setProjectCode(tpSpending.getProjectCode());
        tpExpense.setReason(tpSpending.getReason());
        tpExpense.setRemark(tpSpending.getRemark());
        tpExpense.setSpendingType(spendingTypeEnum == null ? tpSpending.getSpendingType() : spendingTypeEnum.getCode());
        tpExpenseService.save(tpExpense);
        // 附件
        this.copyAttach(mainId, tpMainExpense.getId());
        // 经费
        this.copyBudget(mainId, tpExpense.getId());
        return tpMainExpense.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveForExpenseMerge(String[] mainIds, String applyUser, String applyDept) {
        Double totalMoney = 0D;
        List<String> agentUsers = CollUtil.newArrayList();
        List<TpMain> tpMains = CollUtil.newArrayList();
        for (String mainId : mainIds) {
            // 流程主表
            TpMain tpMain = super.getById(mainId);
            tpMains.add(tpMain);
            if (tpMain == null) {
                log.error("流程主表不存在：mainId={}", mainId);
                throw new RRException("流程主表不存在");
            }
            // 判断是否是请示
            if (!ProcessTypeEnum.findByDeployKey(tpMain.getApplyType()).equals(ProcessTypeEnum.SPENDING)) {
                throw new RRException("此单据不是请示单");
            }
            // 请示
            TpSpending tpSpending = tpSpendingService.findByMainId(mainId);
            if (tpSpending == null) {
                log.error("流程信息不存在：mainId={}", mainId);
                throw new RRException("流程信息不存在");
            }
            // 计算总金额
            totalMoney += tpSpending.getMoney();
            agentUsers.add(tpMain.getAgentUsers());
        }
        // 报销主表
        TpMain tpMainExpense = new TpMain();
        tpMainExpense.setAgentUsers(agentUsers.size() <= 2 ? StrUtil.join(",", agentUsers) : StrUtil.join(",", CollUtil.getAny(agentUsers, 0, 1)).concat("等"));
        tpMainExpense.setApplyDate(new Date());
        tpMainExpense.setTitle("合并报销");
        tpMainExpense.setApplyCode(ProcessTypeEnum.EXPENSE.getPrefix().concat(String.valueOf(Calendar.getInstance().getTimeInMillis()))
                .concat(RandomUtil.randomNumbers(3)));
        tpMainExpense.setApplyDeptCode(applyDept);
        tpMainExpense.setApplyType(ProcessTypeEnum.EXPENSE.getDeployKey());
        tpMainExpense.setApplyUserCode(applyUser);
        tpMainExpense.setState(1);
        super.save(tpMainExpense);
        // 报销信息
        TpExpense tpExpense = new TpExpense();
        tpExpense.setTpMainId(tpMainExpense.getId());
        tpExpense.setIsUsePublic(false);
        tpExpense.setIsExistApply(true);
        tpExpense.setMoney(totalMoney);
        tpExpenseService.save(tpExpense);
        // 更新请示为已报销
        super.update(new UpdateWrapper<TpMain>().in("ID_", mainIds)
                .set("IS_ASSOCIATED_", true)
                .set("ASSOCIATED_CODE_", tpMainExpense.getApplyCode())
        );
        tpSpendingService.update(new UpdateWrapper<TpSpending>().in("TP_MAIN_ID_", mainIds)
                .set("IS_EXPENSE_", true)
        );
        // 更新其他信息
        Set<String> depts = CollUtil.newHashSet();
        tpMains.stream().forEach(o -> {
            // 保存关联信息
            TpAssociated tpAssociated = TpAssociated.builder()
                    .processCode(o.getApplyCode())
                    .tpMainId(tpMainExpense.getId())
                    .build();
            tpAssociatedService.save(tpAssociated);
            // 保存附件
            this.copyAttach(o.getId(), tpMainExpense.getId());
            // 明细信息
            this.copyBudget(o.getId(), tpExpense.getId());
            if (!depts.contains(o.getApplyDeptCode())) {
                depts.add(o.getApplyDeptCode());
            }
        });
        if (depts.size() > 1) {
            tpExpense.setSpendingType(SpendingTypeEnum.type_4.getCode());
        }
        return tpMainExpense.getId();
    }

    @Override
    public String saveForRepay(String mainId) {
        TpMain tpMain = super.getById(mainId);
        if (tpMain == null) {
            log.error("流程主表不存在：mainId={}", mainId);
            throw new RRException("流程主表不存在");
        }
        // 判断是否是报销单
        if (!ProcessTypeEnum.findByDeployKey(tpMain.getApplyType()).equals(ProcessTypeEnum.EXPENSE)) {
            throw new RRException("此单据不是报销单");
        }
        // 查询借款报销单
        TpExpense tpExpense = tpExpenseService.findByMainId(mainId);
        if (tpExpense == null) {
            log.error("流程信息不存在：mainId={}", mainId);
            throw new RRException("流程信息不存在");
        }
        // 保存还款信息
        TpMain mainRepay = new TpMain();
        BeanUtils.copyProperties(tpMain, mainRepay);
        mainRepay.setApplyDate(new Date());
        mainRepay.setApplyCode(
                ProcessTypeEnum.REPAY.getPrefix().concat(String.valueOf(Calendar.getInstance().getTimeInMillis()))
                        .concat(RandomUtil.randomNumbers(3)));
        mainRepay.setApplyType(ProcessTypeEnum.REPAY.getDeployKey());
        mainRepay.setState(1);
        super.save(mainRepay);
        // 报销信息
        TpRepay tpRepay = new TpRepay();
        BeanUtils.copyProperties(tpExpense, tpRepay);
        tpRepay.setTpMainId(mainRepay.getId());
        tpRepay.setExpenseCode(tpMain.getApplyCode());
        tpRepay.setIsPay(false);
        tpRepay.setCzjResult(false);
        tpRepay.setIsAppoint(false);
        tpRepayService.save(tpRepay);
        return mainRepay.getId();
    }

    @Override
    public PzForInvoiceVO findPzForInvoice(String applyCode) {
        return this.baseMapper.findPzForInvoice(applyCode);
    }

    @Override
    public Map<String, Object> queryStatistical() {
        List<Map<String, Object>> list = this.baseMapper.queryStatistical();
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public Map<String, Object> queryAvgForDealTime() {
        List<Map<String, Object>> list = this.baseMapper.queryAvgForDealTime();
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public Integer curFinancialYear() {
        return redisUtils.hget(Constant.REDIS_FINANCIAL, "year", Integer.class);
    }

    @Override
    public Long queryAppointDeal() {
        return this.baseMapper.queryAppointDeal();
    }

    /**
     * 复制明细信息
     *
     * @param oldMainId
     * @param newMainId
     */
    private void copyBudget(String oldMainId, String newMainId) {
        List<TpsFundingSource> tpsFundingSourceList = tpsFundingSourceService.findByMainId(oldMainId);
        tpsFundingSourceList.stream().forEach(o -> {
            TpeFundingSource tpeFundingSource = new TpeFundingSource();
            BeanUtils.copyProperties(o, tpeFundingSource);
            tpeFundingSource.setId(null);
            tpeFundingSource.setTpExpenseId(newMainId);
            // 预算冻结转换
            String freezsId = budgetFreezsInter.converBudgetFreezs(o.getBudgetFreezsId(), ProcessTypeEnum.EXPENSE.getDeployKey(), "生成报销单");
            tpeFundingSource.setBudgetFreezsId(freezsId);
            tpeFundingSourceService.save(tpeFundingSource);
        });
    }

    /**
     * 复制附件
     *
     * @param oldMainId
     * @param newMainId
     */
    private void copyAttach(String oldMainId, String newMainId) {
        List<TpAttachment> tpAttachmentList = tpAttachmentService.findEntityByMainId(oldMainId);
        tpAttachmentList.stream().forEach(attach -> {
            TpAttachment tpAttachmentExpense = new TpAttachment();
            BeanUtils.copyProperties(attach, tpAttachmentExpense);
            tpAttachmentExpense.setId(null);
            tpAttachmentExpense.setTpMainId(newMainId);
            // 图片
            try {
                File attachFile = FileUtil.file(attach.getPathLocal());
                if (attachFile.exists()) {
                    @Cleanup InputStream is = new FileInputStream(attach.getPathLocal());
                    File outputFile = fileUtils.updateFile(is, tpAttachmentExpense.getRealName(), LocalDate.now().toString().split("-"));
                    tpAttachmentExpense.setGenerateName(outputFile.getName().substring(0, outputFile.getName().lastIndexOf(".")));
                    tpAttachmentExpense.setPathLocal(outputFile.getPath());
                    tpAttachmentExpense.setPathRelative(fileUtils.getNoBasePath(outputFile.getPath()).replace(File.separator, "/"));
                    tpAttachmentService.save(tpAttachmentExpense);
                }
            } catch (IOException e) {
                log.error("", e);
                throw new RRException("");
            }
        });
    }

    private PzTicketVO buildSpending(PzRequestVO pzRequestVO, List<PzTripVO> pzTripVOS, List<PzBudgetVO> budgetVOS) {
        // 查询出差
        if (pzTripVOS != null && !pzTripVOS.isEmpty()) {
            String reason = pzRequestVO.getPzMainVO().getReason();
            Set<String> expenseUnits = CollUtil.newLinkedHashSet();
            Set<LocalDate> tripTimes = CollUtil.newLinkedHashSet();
            Set<String> traffics = CollUtil.newLinkedHashSet();
            Set<String> places = CollUtil.newLinkedHashSet();
            StringBuffer reasonBuffer = new StringBuffer();
            reasonBuffer.append(reason).append("<br/>");
            pzTripVOS.stream().limit(4).forEach(pzTraffic -> {
                reasonBuffer.append(pzTraffic.toString()).append("<br/>");
                if (StrUtil.isNotBlank(pzTraffic.getExpenseUnit())) {
                    expenseUnits.add(pzTraffic.getExpenseUnit());
                }
                if (pzTraffic.getStartTime() != null) {
                    tripTimes.add(pzTraffic.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
                }
                if (pzTraffic.getEndTime() != null) {
                    tripTimes.add(pzTraffic.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
                }
                if (StrUtil.isNotBlank(pzTraffic.getTraffic())) {
                    traffics.add(pzTraffic.getTraffic());
                }
                if (StrUtil.isNotBlank(pzTraffic.getStartPlace()) && StrUtil.isNotBlank(pzTraffic.getEndPlace())) {
                    places.add(pzTraffic.getStartPlace() + " 至 " + pzTraffic.getEndPlace());
                }
            });
            String[] placeArr = places.toArray(new String[0]);
            pzRequestVO.setPzTripTicketVO(PzTripTicketVO.builder()
                    .reasonTrip(reason)
                    .expenseUnit(expenseUnits.isEmpty() ? "" : StrUtil.join(",", expenseUnits))
                    .traffic(traffics.isEmpty() ? "" : StrUtil.join(",", traffics))
                    .tripTime(tripTimes.isEmpty() ? "" : "自 " + Collections.min(tripTimes).format(DateTimeFormatter.ofPattern("MM月dd日")) + " 至 " + Collections.max(tripTimes).format(DateTimeFormatter.ofPattern("MM月dd日")))
                    .place1(places.size() > 0 ? placeArr[0] : "")
                    .place2(places.size() > 1 ? placeArr[1] : "")
                    .place3(places.size() > 2 ? placeArr[2] : "")
                    .place4(places.size() > 3 ? placeArr[3] : "")
                    .build());
        }
        if (budgetVOS != null && budgetVOS.size() > 0) {
            StringBuilder budgetNameBuilder = new StringBuilder();
            List<String> budgetNames = budgetVOS.stream().limit(2).map(pzBudget -> pzBudget.getProjectName()).collect(Collectors.toList());
            for (int i = 0; i < budgetNames.size(); i++) {
                if (StrUtil.isNotBlank(budgetNames.get(i))) {
                    budgetNameBuilder.append(budgetNames.get(i));
                }
                if (budgetVOS.size() > 2 && i + 1 == 2) {
                    budgetNameBuilder.append("，等");
                } else {
                    budgetNameBuilder.append("<br/>");
                }
            }
            pzRequestVO.setBudgetStr(budgetNameBuilder.toString());
        }

        // 单据基本信息
        String alias = pzConf.getInit().getAlias();
        PrintTmpl printTmpl = null;
        if (StrUtil.equals(alias, "dq")) {
            printTmpl = new PrintTmplDQ();
        } else {
            printTmpl = new PrintTmplXZ();
        }
        PrintTmplContext printTmplContext = new PrintTmplContext(printTmpl);
        String templateName = printTmplContext.exec(pzRequestVO.getPzMainVO().getMoney());
        pzRequestVO.setSpendingName(SpendingTypeEnum.findByCode(pzRequestVO.getPzMainVO().getSpendingType()).getSpendingName());
        return PzTicketVO.builder()
                .templateName(templateName)
                .pz(pzRequestVO)
                .build();
    }

    /**
     * 查询双高
     *
     * @param mainIds
     * @return
     */
    private Map<String, List<BudgetSGForFreezsVO>> sgInfos(List<String> mainIds) {
        if (mainIds == null || mainIds.isEmpty() || budgetInfoInter == null || budgetFreezsInter == null) {
            return CollUtil.newHashMap();
        }
        QueryWrapper<TpMain> queryWrapper = Wrappers.query();
        queryWrapper.in("ID_", mainIds);
        List<TpMain> list = this.list(queryWrapper);
        // 冻结ID-单据主表ID
        Map<String, String> freezeMainMap = CollUtil.newHashMap();
        // 预算ID-单据主表ID
        Map<String, List<String>> budgetInfoMainMap = CollUtil.newHashMap();
        List<String> freezsIds = CollUtil.newArrayList();
        List<String> budgetInfoIds = CollUtil.newArrayList();
        list.forEach(o -> {
            ProcessTypeEnum processTypeEnum = ProcessTypeEnum.findByDeployKey(o.getApplyType());
            switch (processTypeEnum) {
                case SPENDING:
                    List<TpsFundingSource> byMainId = tpsFundingSourceService.findByMainId(o.getId());
                    byMainId.forEach(fs -> {
                        freezeMainMap.put(fs.getBudgetFreezsId(), o.getId());
                        freezsIds.add(fs.getBudgetFreezsId());
                        if (!budgetInfoMainMap.containsKey(fs.getBudgetInfoId())) {
                            budgetInfoMainMap.put(fs.getBudgetInfoId(), CollUtil.newArrayList());
                        }
                        budgetInfoMainMap.get(fs.getBudgetInfoId()).add(o.getId());
                        budgetInfoIds.add(fs.getBudgetInfoId());
                    });
                    break;
                case EXPENSE:
                    List<TpeFundingSource> byMainId1 = tpeFundingSourceService.findByMainId(o.getId());
                    byMainId1.forEach(fs -> {
                        freezeMainMap.put(fs.getBudgetFreezsId(), o.getId());
                        freezsIds.add(fs.getBudgetFreezsId());
                        if (!budgetInfoMainMap.containsKey(fs.getBudgetInfoId())) {
                            budgetInfoMainMap.put(fs.getBudgetInfoId(), CollUtil.newArrayList());
                        }
                        budgetInfoMainMap.get(fs.getBudgetInfoId()).add(o.getId());
                        budgetInfoIds.add(fs.getBudgetInfoId());
                    });
                    break;
                case REPAY:
                    List<TpRepayBudget> byMainId2 = tpRepayBudgetService.findByMainId(o.getId());
                    byMainId2.forEach(fs -> {
                        freezeMainMap.put(fs.getBudgetFreezsId(), o.getId());
                        freezsIds.add(fs.getBudgetFreezsId());
                        if (!budgetInfoMainMap.containsKey(fs.getBudgetInfoId())) {
                            budgetInfoMainMap.put(fs.getBudgetInfoId(), CollUtil.newArrayList());
                        }
                        budgetInfoMainMap.get(fs.getBudgetInfoId()).add(o.getId());
                        budgetInfoIds.add(fs.getBudgetInfoId());
                    });
                    break;
            }
        });
        // 已保存的双高项目
        List<BudgetSGForFreezsVO> sgByFreeze = budgetFreezsInter.findSGByFreeze(freezsIds);
        // 整理返回数据
        Map<String, List<BudgetSGForFreezsVO>> mainSGMap = CollUtil.newHashMap();
        sgByFreeze.forEach(o -> {
            String mainId = freezeMainMap.get(o.getFreezsId());
            if (!mainSGMap.containsKey(mainId)) {
                mainSGMap.put(mainId, CollUtil.newArrayList());
            }
            mainSGMap.get(mainId).add(o);
        });
        return mainSGMap;
    }


}


